home *** CD-ROM | disk | FTP | other *** search
Wrap
Text File | 2000-09-28 | 11.4 KB | 329 lines | [ TEXT/MPS ]
/* File: ShapeUtilitiesPaths.c Contains: QuickDraw GX to PostScript conversion code. DissectPath() converts a polygon or path shape into an equivalent picture whose elements each have no more points than the limit specified. The callers preference for horizontal versus vertical splitting is accomodated as much as possible. Additionally, a function can be passed to override the default point counting Version: Technology: Quickdraw GX 1.1.x Copyright: © 1989-1997 by Apple Computer, Inc., all rights reserved. */ #undef SKIA_BUG_2PICTURE // Converting to picture doubles transform (mapping) #undef SKIA_BUG_RECT // My favorite gx graphics bug #ifdef SKIA_BUG_RECT // Normal //#define BAD_RECT_TYPE gxRectangleType // Helps BUG3, not BUG1 #define BAD_RECT_TYPE gxPolygonType // prevents clipping problem (BUG1) // Keeps from scrolling death (BUG3) -- but doesnt draw correctly //#define BAD_RECT_TYPE gxPathType #endif SKIA_BUG_RECT #undef VERBOSE // Talk through analysis, if set // allow multiple references to single label #define resumeLabel(exception) #include "GXToPSBuildConfig.h" #include <GXGraphics.h> #include "GXExceptions.h" #include "ShapeUtilities.h" #include "IOUtilities.h" /* Split the shape in half */ /** D.L had to write slightly new version of routine due to the fact that the paramters to GXIntersectShape had to be reversed. The rectangle (shapeSplitter here) needs to be the second paramter to intersect shape. The shape we are splitting needs to be the target. This is to fix bug #1131755. Actually, this ends up simplifying the code. We no longer need to put the shape's transform, ink and style on the rectangles since the rectangles are not the target shape anymore. Ken, take a look at my cleanup logic. I'm not sure if I followed your methods. (DisposeShapeAt, etc…) **/ OSErr SplitPath(gxShape *thisShape, gxRectangle *shapeSize, Boolean splitH, gxShape *newShapeHalf, gxRectangle *sectSizeHalf); OSErr SplitPath(gxShape *thisShape, gxRectangle *shapeSize, Boolean splitH, gxShape *newShapeHalf, gxRectangle *sectSizeHalf) { OSErr status; gxShape shapeSplitter; // rectangle used to split the shape. /** Find the rectangles with which to split the shape **/ sectSizeHalf[0].left = sectSizeHalf[1].left = shapeSize->left; sectSizeHalf[0].top = sectSizeHalf[1].top = shapeSize->top; sectSizeHalf[0].right = sectSizeHalf[1].right = shapeSize->right; sectSizeHalf[0].bottom = sectSizeHalf[1].bottom = shapeSize->bottom; /* Split into halves */ if (splitH) { /* Horizontal split? */ sectSizeHalf[1].left = sectSizeHalf[0].right -= (shapeSize->right - shapeSize->left) >> 1; /* Divide in half */ } else { /* Vertical split */ sectSizeHalf[1].top = sectSizeHalf[0].bottom -= (shapeSize->bottom - shapeSize->top) >> 1; /* Divide in half */ } /** Intersect the shape with the two halves **/ shapeSplitter = GXNewRectangle(§SizeHalf[0]); nrequire(status = GXGetGraphicsError(nil), failed_makeSplitter); // First half newShapeHalf[0] = GXCopyToShape(nil, *thisShape); nrequire(status = GXGetGraphicsError(nil), failed_firstCopy); GXIntersectShape(newShapeHalf[0], shapeSplitter); nrequire(status = GXGetGraphicsError(nil), failed_firstHalf); // second half newShapeHalf[1] = GXCopyToShape(nil, *thisShape); nrequire(status = GXGetGraphicsError(nil), failed_secondCopy); GXSetRectangle(shapeSplitter, §SizeHalf[1]); GXIntersectShape(newShapeHalf[1], shapeSplitter); nrequire(status = GXGetGraphicsError(nil), failed_secondHalf); failed_secondHalf: if (status != noErr) if (newShapeHalf[1] != nil) GXDisposeShape(newShapeHalf[1]); // DL 7/8/97 failed_secondCopy: failed_firstHalf: if (status != noErr) // DL 7/8/97 if (newShapeHalf[0] != nil) GXDisposeShape(newShapeHalf[0]); failed_firstCopy: GXDisposeShape(shapeSplitter); failed_makeSplitter: return(status); } #ifdef leaveParametersReversed /* Split the shape in half */ OSErr SplitPath(thisShape, shapeSize, splitH, newShapeHalf, sectSizeHalf) gxShape *thisShape; gxRectangle *shapeSize; Boolean splitH; gxShape *newShapeHalf; gxRectangle *sectSizeHalf; { OSErr status; /* duplicate rectangle */ sectSizeHalf[0].left = sectSizeHalf[1].left = shapeSize->left; sectSizeHalf[0].top = sectSizeHalf[1].top = shapeSize->top; sectSizeHalf[0].right = sectSizeHalf[1].right = shapeSize->right; sectSizeHalf[0].bottom = sectSizeHalf[1].bottom = shapeSize->bottom; /* Split into halves */ if (splitH) { /* Horizontal split? */ sectSizeHalf[1].left = sectSizeHalf[0].right -= (shapeSize->right - shapeSize->left) >> 1; /* Divide in half */ } else { /* Vertical split */ sectSizeHalf[1].top = sectSizeHalf[0].bottom -= (shapeSize->bottom - shapeSize->top) >> 1; /* Divide in half */ } /* Create section areas */ newShapeHalf[0] = GXNewRectangle(§SizeHalf[0]); nrequire(status = GXGetGraphicsError(nil), failed_NewRectangle0); newShapeHalf[1] = GXNewRectangle(§SizeHalf[1]); nrequire(status = GXGetGraphicsError(nil), failed_NewRectangle1); /* Give the rectangles the ink of the shape we are splitting so the returned pieces have it */ GXSetShapeInk(newShapeHalf[0], GXGetShapeInk(*thisShape)); GXSetShapeInk(newShapeHalf[1], GXGetShapeInk(*thisShape)); /* Give the rectangles the Transform of the shape we are splitting so the returned pieces have it */ GXSetShapeTransform(newShapeHalf[0], GXGetShapeTransform(*thisShape)); GXSetShapeTransform(newShapeHalf[1], GXGetShapeTransform(*thisShape)); /* Give the rectangles the Style of the shape we are splitting so the returned pieces have it */ GXSetShapeStyle(newShapeHalf[0], GXGetShapeStyle(*thisShape)); GXSetShapeStyle(newShapeHalf[1], GXGetShapeStyle(*thisShape)); #ifdef SKIA_BUG_RECT /* gx graphics bug work-around (rectangles BAD, polygons & paths GOOD!) */ GXSetShapeType(newShapeHalf[0], BAD_RECT_TYPE); GXSetShapeType(newShapeHalf[1], BAD_RECT_TYPE); #endif SKIA_BUG_RECT /* Find intersections */ GXIntersectShape(newShapeHalf[0], *thisShape); GXIntersectShape(newShapeHalf[1], *thisShape); nrequire(status = GXGetGraphicsError(nil), failed_SectShape); return(noErr); /* OK */ /* BAILOUTS */ failed_SectShape: DisposeShapeAt(&newShapeHalf[1]); /* Don't litter! (nil pointer out) */ failed_NewRectangle1: DisposeShapeAt(&newShapeHalf[0]); /* Don't litter! (nil pointer out) */ failed_NewRectangle0: return(status); /* Propagate error status */ } #endif /* Return number of points (all contours) -- Central in case parms change */ #define CountPoints(theShape, num) ((*countFunct)(theShape, 0, num)) /* Must use wrapper here! */ OSErr DefaultCountPoints(gxShape source, long contour, long *num); OSErr DefaultCountPoints(gxShape source, long contour, long *num) { *num = (GXCountShapePoints(source, contour)); /* Default count function */ return(noErr); } // DefaultCountPoints #ifdef PATCH_IMAGE /* Use smaller limit for testing purposes */ # define TRY_LIMIT 20 #else PATCH_IMAGE /* If this limit is ever hit, the user died of old age! */ # define TRY_LIMIT 0x7FFFFFFF #endif PATCH_IMAGE /* Chop that shape! */ OSErr ShUDissectPath(gxShape theShape, long limit, Boolean splitH, OSErr (*countFunct)(gxShape aShape, long contour, long *numPoints)) { OSErr status; long count1, count2; gxShape theSource, thisShape, newShapeHalf[2], newShapeQuarter[4]; gxRectangle shapeSize, sectSizeHalf[2], sectSizeQuarter[4]; long shapeCount, shapeCountHalf[2], shapeCountQuarter[4]; long tries = 0; /* To prevent infinite loops, or just plain boredom! */ /* Validate shape type */ switch (GXGetShapeType(theShape)) { case gxPolygonType: case gxPathType: break; /* These are great! */ default: GXPostGraphicsError(illegal_type_for_shape); /* Yell real loud! */ return(illegal_type_for_shape); /* Bail out */ } if (countFunct == nil) /* Was a counting function supplied? */ countFunct = DefaultCountPoints; /* Use default, if not */ /* Create in and out buckets (pictures) */ GXSetShapeType(theShape, gxPictureType); /* Convert to picture */ nrequire(status = GXGetGraphicsError(nil), failed_SetShapeType); /* Create in bucket */ theSource = GXCopyToShape(nil, theShape); /* Make a working copy */ nrequire(status = GXGetGraphicsError(nil), failed_CopyToShape); /* Create return bucket */ GXSetPictureParts(theShape, 1, 1, 0, nil, nil, nil, nil); /* Clean it out */ nrequire(status = GXGetGraphicsError(nil), failed_SetPictureParts); while (GXGetPicture(theSource, nil, nil, nil, nil) && GXGetPictureParts(theSource, 1, 1, &thisShape, nil, nil, nil)) { /* Call GetPicture() first to void bad index when no elements left */ status = CountPoints(thisShape, &count1); nrequire(status, failed_count); if ( (tries > TRY_LIMIT) || ( (shapeCount = count1) <= limit) ) { /* Small enough? */ GXSetPictureParts(theShape, 0, 0, 1, &thisShape, nil, nil, nil); /* Append the part */ GXSetPictureParts(theSource, 1, 1, 0, nil, nil, nil, nil); /* Delete the part */ nrequire(status = GXGetGraphicsError(nil), failed_SetPictureParts0); } else { /* Need to split */ ++tries; /* Log another split */ GXGetShapeBounds(thisShape, (long) 0, &shapeSize); /* Size the shape */ nrequire(status = GXGetGraphicsError(nil), failed_GetShapeBounds); status = SplitPath(&thisShape, &shapeSize, splitH, &newShapeHalf[0], §SizeHalf[0]); nrequire(status, failed_SplitPath1); status = CountPoints(newShapeHalf[0], &count1); if (status == noErr) status = CountPoints(newShapeHalf[1], &count2); nrequire(status, failed_count); if (( (shapeCountHalf[0] = count1) < shapeCount) && ( (shapeCountHalf[1] = count2) < shapeCount) ){ /* Improved? */ GXSetPictureParts(theSource, 1, 1, 2, &newShapeHalf[0], nil, nil, nil); /* Replace the part */ nrequire(status = GXGetGraphicsError(nil), failed_SetPictureParts1); } else { /* Made matters worse! */ /* Split other axis */ status = SplitPath(&thisShape, &shapeSize, ! splitH, &newShapeQuarter[0], §SizeQuarter[0]); nrequire(status, failed_SplitPath2); status = CountPoints(newShapeQuarter[0], &count1); if (status == noErr) status = CountPoints(newShapeQuarter[1], &count2); nrequire(status, failed_count); if (( (shapeCountQuarter[0] = count1) < shapeCount) && ( (shapeCountQuarter[1] = count2) < shapeCount) ) { /* Improved? */ GXSetPictureParts(theSource, 1, 1, 2, &newShapeQuarter[0], nil, nil, nil); /* Replace the part */ nrequire(status = GXGetGraphicsError(nil), failed_SetPictureParts2); } else { /* Do lesser of the evils */ GXSetPictureParts(theSource, 1, 1, 2, &newShapeHalf[0], nil, nil, nil); /* Replace the part */ nrequire(status = GXGetGraphicsError(nil), failed_SetPictureParts2b); } GXDisposeShape(newShapeQuarter[0]); /* Don't litter! */ GXDisposeShape(newShapeQuarter[1]); /* Don't litter! */ } GXDisposeShape(newShapeHalf[0]); /* Don't litter! */ GXDisposeShape(newShapeHalf[1]); /* Don't litter! */ } } GXDisposeShape(theSource); /* Don't litter! */ return(noErr); /* OK */ /* BAILOUTS */ failed_SetPictureParts2b: failed_SetPictureParts2: failed_SetPictureParts1: failed_SetPictureParts0: failed_SplitPath2: failed_SplitPath1: failed_GetShapeBounds: failed_SetPictureParts: failed_count: GXDisposeShape(theSource); /* Don't litter! */ failed_CopyToShape: #ifndef SKIA_BUG_2PICTURE failed_DisposeTransform: failed_NewTransform: failed_GetPictureParts: #endif SKIA_BUG_2PICTURE failed_SetShapeType: return(status); /* Propagate error */ }